home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / sbin / update-rc.d < prev    next >
Encoding:
Text File  |  2009-03-31  |  6.8 KB  |  271 lines

  1. #! /usr/bin/perl
  2. #
  3. # update-rc.d    Update the links in /etc/rc[0-9S].d/
  4. #
  5.  
  6. use strict;
  7. use warnings;
  8.  
  9. my $initd = "/etc/init.d";
  10. my $etcd  = "/etc/rc";
  11. my $notreally = 0;
  12.  
  13. # Print usage message and die.
  14.  
  15. sub usage {
  16.     print STDERR "update-rc.d: error: @_\n" if ($#_ >= 0);
  17.     print STDERR <<EOF;
  18. usage: update-rc.d [-n] [-f] <basename> remove
  19.        update-rc.d [-n] <basename> defaults [NN | SS KK]
  20.        update-rc.d [-n] <basename> start|stop NN runlvl [runlvl] [...] .
  21.         -n: not really
  22.         -f: force
  23. EOF
  24.     exit (1);
  25. }
  26.  
  27. # Check out options.
  28. my $force;
  29.  
  30. while($#ARGV >= 0 && ($_ = $ARGV[0]) =~ /^-/) {
  31.     shift @ARGV;
  32.     if (/^-n$/) { $notreally++; next }
  33.     if (/^-f$/) { $force++; next }
  34.     if (/^-h|--help$/) { &usage; }
  35.     &usage("unknown option");
  36. }
  37.  
  38. # Action.
  39.  
  40. &usage() if ($#ARGV < 1);
  41. my $bn = shift @ARGV;
  42.  
  43. unless ($bn =~ m/[a-zA-Z0-9+.-]+/) {
  44.     print STDERR "update-rc.d: illegal character in name '$bn'\n";
  45.     exit (1);
  46. }
  47.  
  48. if ($ARGV[0] ne 'remove') {
  49.     if (! -f "$initd/$bn") {
  50.     print STDERR "update-rc.d: $initd/$bn: file does not exist\n";
  51.     exit (1);
  52.     }
  53.     &parse_lsb_header("$initd/$bn");
  54. } elsif (-f "$initd/$bn") {
  55.     if (!$force) {
  56.     printf STDERR "update-rc.d: $initd/$bn exists during rc.d purge (use -f to force)\n";
  57.     exit (1);
  58.     }
  59. }
  60.  
  61. my @startlinks;
  62. my @stoplinks;
  63.  
  64. $_ = $ARGV[0];
  65. if    (/^remove$/)       { &checklinks ("remove"); }
  66. elsif (/^defaults$/)     { &defaults; &makelinks }
  67. elsif (/^multiuser$/)    { &multiuser; &makelinks }
  68. elsif (/^(start|stop)$/) { &startstop; &makelinks; }
  69. else                     { &usage; }
  70.  
  71. exit (0);
  72.  
  73. # Check if there are links in /etc/rc[0-9S].d/ 
  74. # Remove if the first argument is "remove" and the links 
  75. # point to $bn.
  76.  
  77. sub is_link () {
  78.     my ($op, $fn, $bn) = @_;
  79.     if (! -l $fn) {
  80.     print STDERR "update-rc.d: warning: $fn is not a symbolic link\n";
  81.     return 0;
  82.     } else {
  83.     my $linkdst = readlink ($fn);
  84.     if (! defined $linkdst) {
  85.         die ("update-rc.d: error reading symbolic link: $!\n");
  86.     }
  87.     if (($linkdst ne "../init.d/$bn") && ($linkdst ne "$initd/$bn")) {
  88.         print STDERR "update-rc.d: warning: $fn is not a link to ../init.d/$bn or $initd/$bn\n";
  89.         return 0;
  90.     }
  91.     }
  92.     return 1;
  93. }
  94.  
  95. sub checklinks {
  96.     my ($i, $found, $fn, $islnk);
  97.  
  98.     print " Removing any system startup links for $initd/$bn ...\n"
  99.     if (defined $_[0] && $_[0] eq 'remove');
  100.  
  101.     $found = 0;
  102.  
  103.     foreach $i (0..9, 'S') {
  104.     unless (chdir ("$etcd$i.d")) {
  105.         next if ($i =~ m/^[789S]$/);
  106.         die("update-rc.d: chdir $etcd$i.d: $!\n");
  107.     }
  108.     opendir(DIR, ".");
  109.     my $saveBN=$bn;
  110.     $saveBN =~ s/\+/\\+/g;
  111.     foreach $_ (readdir(DIR)) {
  112.         next unless (/^[SK]\d\d$saveBN$/);
  113.         $fn = "$etcd$i.d/$_";
  114.         $found = 1;
  115.         $islnk = &is_link ($_[0], $fn, $bn);
  116.         next unless (defined $_[0] and $_[0] eq 'remove');
  117.         if (! $islnk) {
  118.         print "   $fn is not a link to ../init.d/$bn; not removing\n"; 
  119.         next;
  120.         }
  121.         print "   $etcd$i.d/$_\n";
  122.         next if ($notreally);
  123.         unlink ("$etcd$i.d/$_") ||
  124.         die("update-rc.d: unlink: $!\n");
  125.     }
  126.     closedir(DIR);
  127.     }
  128.     $found;
  129. }
  130.  
  131. sub parse_lsb_header {
  132.     my $initdscript = shift;
  133.     my %lsbinfo;
  134.     my $lsbheaders = "Provides|Required-Start|Required-Stop|Default-Start|Default-Stop";
  135.     open(INIT, "<$initdscript") || die "error: unable to read $initdscript";
  136.     while (<INIT>) {
  137.         chomp;
  138.         $lsbinfo{'found'} = 1 if (m/^\#\#\# BEGIN INIT INFO$/);
  139.         last if (m/\#\#\# END INIT INFO$/);
  140.         if (m/^\# ($lsbheaders):\s*(\S?.*)$/i) {
  141.         $lsbinfo{lc($1)} = $2;
  142.         }
  143.     }
  144.     close(INIT);
  145.  
  146.     # Check that all the required headers are present
  147.     if (!$lsbinfo{found}) {
  148.     printf STDERR "update-rc.d: warning: $initdscript missing LSB information\n";
  149.     printf STDERR "update-rc.d: see <http://wiki.debian.org/LSBInitScripts>\n";
  150.     } else {
  151.         for my $key (split(/\|/, lc($lsbheaders))) {
  152.             if (!exists $lsbinfo{$key}) {
  153.                 print STDERR "update-rc.d: warning: $initdscript missing LSB keyword '$key'\n";
  154.             }
  155.         }
  156.     }
  157. }
  158.  
  159.  
  160. # Process the arguments after the "defaults" keyword.
  161.  
  162. sub defaults {
  163.     my ($start, $stop) = (20, 20);
  164.  
  165.     &usage ("defaults takes only one or two codenumbers") if ($#ARGV > 2);
  166.     $start = $stop = $ARGV[1] if ($#ARGV >= 1);
  167.     $stop  =         $ARGV[2] if ($#ARGV >= 2);
  168.     &usage ("codenumber must be a number between 0 and 99")
  169.     if ($start !~ /^\d\d?$/ || $stop  !~ /^\d\d?$/);
  170.  
  171.     $start = sprintf("%02d", $start);
  172.     $stop  = sprintf("%02d", $stop);
  173.  
  174.     $stoplinks[$_]  = "K$stop"  for (0, 1, 6);
  175.     $startlinks[$_] = "S$start" for (2, 3, 4, 5);
  176.  
  177.     1;
  178. }
  179.  
  180. # Process the arguments after the "multiuser" keyword.
  181.  
  182. sub multiuser {
  183.     my ($start, $stop) = (20, 20);
  184.  
  185.     print STDERR "update-rc.d: warning: multiuser is deprecated; specify runlevels manually\n";
  186.     &usage ("multiuser takes only one or two codenumbers") if ($#ARGV > 2);
  187.     $start = $stop = $ARGV[1] if ($#ARGV >= 1);
  188.     $stop  =         $ARGV[2] if ($#ARGV >= 2);
  189.     &usage ("codenumber must be a number between 0 and 99")
  190.     if ($start !~ /^\d\d?$/ || $stop  !~ /^\d\d?$/);
  191.  
  192.     $start = sprintf("%02d", $start);
  193.     $stop  = sprintf("%02d", $stop);
  194.  
  195.     $stoplinks[1] = "K$stop";
  196.     $startlinks[2] = $startlinks[3] =
  197.     $startlinks[4] = $startlinks[5] = "S$start";
  198.  
  199.     1;
  200. }
  201.  
  202. # Process the arguments after the start or stop keyword.
  203.  
  204. sub startstop {
  205.  
  206.     my($letter, $NN, $level);
  207.  
  208.     while ($#ARGV >= 0) {
  209.     if    ($ARGV[0] eq 'start') { $letter = 'S'; }
  210.     elsif ($ARGV[0] eq 'stop')  { $letter = 'K' }
  211.     else {
  212.         &usage("expected start|stop");
  213.     }
  214.  
  215.     if ($ARGV[1] !~ /^\d\d?$/) {
  216.         &usage("expected NN after $ARGV[0]");
  217.     }
  218.     $NN = sprintf("%02d", $ARGV[1]);
  219.  
  220.     shift @ARGV; shift @ARGV;
  221.     $level = shift @ARGV;
  222.         &usage("action with list of runlevels not terminated by \".\"")
  223.             if ($ARGV[$#ARGV] ne '.');
  224.     do {
  225.         if ($level !~ m/^[0-9S]$/) {
  226.         &usage(
  227.                "expected runlevel [0-9S] (did you forget \".\" ?)");
  228.         }
  229.         if (! -d "$etcd$level.d") {
  230.         print STDERR
  231.             "update-rc.d: $etcd$level.d: no such directory\n";
  232.         exit(1);
  233.         }
  234.         $level = 99 if ($level eq 'S');
  235.         $startlinks[$level] = "$letter$NN" if ($letter eq 'S');
  236.         $stoplinks[$level]  = "$letter$NN" if ($letter eq 'K');
  237.     } while (($level = shift @ARGV) ne '.');
  238.     }
  239.     1;
  240. }
  241.  
  242. # Create the links.
  243.  
  244. sub makelinks {
  245.     my($t, $i);
  246.     my @links;
  247.  
  248.     if (&checklinks) {
  249.     print " System startup links for $initd/$bn already exist.\n";
  250.     exit (0);
  251.     }
  252.     print " Adding system startup for $initd/$bn ...\n";
  253.  
  254.     # nice unreadable perl mess :)
  255.  
  256.     for($t = 0; $t < 2; $t++) {
  257.     @links = $t ? @startlinks : @stoplinks;
  258.     for($i = 0; $i <= $#links; $i++) {
  259.         my $lvl = $i;
  260.         $lvl = 'S' if ($i == 99);
  261.         next if (!defined $links[$i] or $links[$i] eq '');
  262.         print "   $etcd$lvl.d/$links[$i]$bn -> ../init.d/$bn\n";
  263.         next if ($notreally);
  264.         symlink("../init.d/$bn", "$etcd$lvl.d/$links[$i]$bn")
  265.         || die("update-rc.d: symlink: $!\n");
  266.     }
  267.     }
  268.  
  269.     1;
  270. }
  271.